﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace InDepth2Demo.Chapter11
{
    /// <summary>
    /// 11.1 LINQ 介绍
    /// </summary>
    internal class IntroducingLINQ
    {
        public static void Call()
        {
            var people = People.GetSamplePeoples();
            var adultNames = from person in people
                             where person.Age >= 18
                             select person.Name;
        }

        public static void Call2()
        {
            var source = new Dummy<string>();                       // 创建用于查询的数据源
            var query = from dummy in source                        // 通过查询表达式来调用方法
                        where dummy.ToString() == "Ignored"
                        select "Anything";
            //这段代码首先会打印出 Where called，接着会打印 Select called

            // 查询表达式会被编译器转译为如下的这段代码：
            var query2 = source.Where(dummy => dummy.ToString() == "Ignored")
                                .Select(dummy => "Anything");

            //IEnumerable<string> query = from user in SampleData.AllUsers
            //                            select user.Name;

        }

        public static void Call3()
        {
            // Join
            //var query = from defect in SampleData.AllDefects
            //            join subscription in SampleData.AllSubscriptions
            //            on defect.Project equals subscription.Project
            //            select new { defect.Summary, subscription.EmailAddress };

            // Join 方法：
            //public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
            //  this IEnumerable<TOuter> outer,
            //  IEnumerable<TInner> inner,
            //  Func<TOuter, TKey> outerKeySelector,
            //  Func<TInner, TKey> innerKeySelector,
            //  Func<TOuter, TInner, TResult> resultSelector
            //  )
            //当你记得把内连接和外连接分别看做是右边和左边时，前3个参数的含义显而易见.


            // Join into
            //var query = from defect in SampleData.AllDefects
            //            join subscription in SampleData.AllSubscriptions
            //            on defect.Project equals subscription.Project
            //              into groupedSubscriptions
            //            select new { Defect = defect, Subscription = groupedSubscriptions };

            // GroupJoin
            // public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
            // this IEnumerable<TOuter> outer,
            // IEnumerable<TInner> inner,
            // Func<TOuter, TKey> outerKeySelector,
            // Func<TInner, TKey> innerKeySelector,
            // Func<TOuter, IEnumerable<TInner>, TResult> resultSelector)

            // Lambda 表达式
            //var query = departments.GroupJoin(
            //    students,
            //    d => d.ID, // 左边集合的键选择器
            //    s => s.DepartmentID, // 右边集合的键选择器
            //    (d, g) => new { DepartmentName = d.Name, StudentCount = g.Count() } // 结果选择器
            //);
        }

        //右边序列依赖于左边元素的交叉连接
        public static void Call4()
        {
            var query = from left in Enumerable.Range(1, 4)
                        from right in Enumerable.Range(11, left)
                        select new { Left = left, Right = right };
            //转换为：
            var query1 = Enumerable.Range(1, 4).SelectMany(left => Enumerable.Range(11, left), (left, right) => new { Left = left, Right = right });

            //public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
            //  this IEnumerable<TSource> source,
            //  Func<TSource, IEnumerable<TCollection>> collectionSelector,
            //  Func<TSource, TCollection, TResult> resultSelector)

            foreach (var item in query)
            {
                Console.WriteLine($"Left={item.Left}, Right={item.Right}");
            }
            //输出
            //Left=1, Right=11
            //Left=2, Right=11
            //Left=2, Right=12
            //Left=3, Right=11
            //Left=3, Right=12
            //Left=3, Right=13
            //Left=4, Right=11
            //Left=4, Right=12
            //Left=4, Right=13
            //Left=4, Right=14
        }

        // GROUP BY 和 ORDER BY
        public static void Call5()
        {
            //var query1 = from defect in SampleData.AllDefects
            //             where defect.AssignedTo != null
            //             group defect by defect.AssignedTo;

            //转换为：
            //var query1 = SampleData.AllDefects.Where(defect => defect.AssignedTo != null)
            //                                    .GroupBy(defect => defect.AssignedTo);

            //foreach (var entry in query1)
            //{
            //    Console.WriteLine(entry.Key.Name);
            //    foreach (var defect in entry)
            //    {
            //        Console.WriteLine($"{defect.Severity}, {defect.Summary}");
            //    }
            //    Console.WriteLine();
            //}
        }

        // 《Learning hard C#学习笔记》
        // 使用LINQ返回集合中为偶数的元素
        public static void LinqQuery(List<int> collection)
        {
            // 创建查询表达式来获得集合中为偶数的元素
            var queryResults = from item in collection
                               where item % 2 == 0
                               select item;
            // 输出查询结果
            foreach (var item in queryResults)
            {
                Console.Write(item + "  ");
            }
        }
    }

    //编译器转译调用伪LINQ实现中的方法
    static class Extensions
    {
        public static Dummy<T> Where<T>(this Dummy<T> dummy, Func<T, bool> predicate)       // 声明 Where 扩展方法
        {
            Console.WriteLine("Where called");
            return dummy;
        }
    }

    class Dummy<T>
    {
        public Dummy<U> Select<U>(Func<T, U> selector)          // 声明 Select 实例方法
        {
            Console.WriteLine("Select called");
            return new Dummy<U>();
        }
    }

}
